package com.example.common.utils;

import com.example.common.exception.BizException;
import com.example.common.exception.errcode.ErrCodeBase;
import io.jsonwebtoken.*;
import lombok.*;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class JwtUtils {

    @Setter@Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public static class JwtUser {
        private String id;          //唯一标识
        private String subject;     //面向用户
        private String issuer;      //签发者
        private String audience;    //接收者
        @Setter(AccessLevel.NONE)
        private Date issuedAt;      //签发日期
        private Date expiration;    //过期时间
        private Date notBefore;     //在此时间之前不可用

        private Date lastLoginTime; //上次登录时间
        private Map<String, Object> map; //预留定义字段
        private List<RoleInfo> roleList;   //角色列表

        @Override
        public String toString() {
            return "JwtUser{" +
                    "id='" + id + '\'' +
                    ", subject='" + subject + '\'' +
                    ", issuer='" + issuer + '\'' +
                    ", audience='" + audience + '\'' +
                    ", issuedAt=" + DateUtils.date2Str(issuedAt, DateUtils.DateFormat.format_yyyy_MM_dd$hhmmss) +
                    ", expiration=" + DateUtils.date2Str(expiration, DateUtils.DateFormat.format_yyyy_MM_dd$hhmmss) +
                    ", notBefore=" + DateUtils.date2Str(notBefore, DateUtils.DateFormat.format_yyyy_MM_dd$hhmmss) +
                    ", lastLoginTime=" + lastLoginTime +
                    ", map=" + map +
                    ", roleList=" + roleList +
                    '}';
        }
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public static class RoleInfo {
        private Long roleId;
        private String roleName;
    }

    /**
     * 使用 Jwt 生成 AccessToken 访问令牌
     *
     * @return
     */
    public static String generateAccessToken(JwtUser jwtUser) {
        JwtBuilder jb = Jwts.builder();
        //设置载荷
        {
            jb.setId(jwtUser.getId());                     //设置唯一标识
            jb.setSubject(jwtUser.getSubject());           //设置面向用户
            jb.setIssuer(jwtUser.getIssuer());             //设置签发者
            jb.setAudience(jwtUser.getAudience());         //设置接收者
            jb.setIssuedAt(new Date());                    //设置签发时间
            jb.setExpiration(jwtUser.getExpiration());     //设置过期时间
            jb.setNotBefore(jwtUser.getNotBefore());       //设置在此时间之前不可用
        }
        //设置自定义声明
        {
            jb.claim("lastLoginTime", jwtUser.getLastLoginTime());   //上次登录时间
            jb.claim("roleList", jwtUser.getRoleList());
            jb.claim("map", jwtUser.getMap());
        }
        //设置签名
        {
            jb.signWith(SignatureAlgorithm.HS256, "demo-salt-value");   //设置签名和盐值
        }
        //生成 token
        String token = jb.compact();
        return token;
    }

    /**
     * 解析 token
     *
     * @param token
     */
    public static JwtUser parseToken(String token) {
        JwtParser parser = Jwts.parser();   //解析器
        Claims claims = null;
        try {
            claims = parser
                    .setSigningKey("demo-salt-value")      //设置盐值
                    .parseClaimsJws(token)      //解析token字符串
                    .getBody();
        } catch (ExpiredJwtException e) {
            throw new BizException(ErrCodeBase.TOKEN_EXPIRED_EXCEPTION);
        } catch (UnsupportedJwtException e) {
            e.printStackTrace();
        } catch (MalformedJwtException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }

        JwtUser jwtUser = JwtUser.builder()
                .id(claims.getId())
                .subject(claims.getSubject())
                .issuer(claims.getIssuer())
                .audience(claims.getAudience())
                .issuedAt(claims.getIssuedAt())
                .expiration(claims.getExpiration())
                .notBefore(claims.getNotBefore())
                .lastLoginTime(claims.get("lastLoginTime",Date.class))
                .map(null)
                .roleList(claims.get("roleList",List.class))
                .build();
        return jwtUser;

    }

    public static void main(String[] args) {
        //String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwIiwic3ViIjoiYWRtaW4iLCJpc3MiOiJEZW1v57O757ufIiwiYXVkIjoi5pmu6YCa55So5oi3IiwiaWF0IjoxNjQ3MDQyMDgxLCJleHAiOjE2NDcwNDkyODEsIm5iZiI6MTY0NzA0MjA4MSwibGFzdExvZ2luVGltZSI6MTY0NzA0MjA4MTg3NCwicm9sZUxpc3QiOlt7InJvbGVJZCI6MCwicm9sZU5hbWUiOiLns7vnu5_nrqHnkIblkZgifSx7InJvbGVJZCI6MTUwMjM4NTU1NTAyNjIxMDgxNiwicm9sZU5hbWUiOiLmnLoifSx7InJvbGVJZCI6MTUwMjM4NTg5NDY0MzIwMDAwMCwicm9sZU5hbWUiOiLlv5cifSx7InJvbGVJZCI6MTUwMjM4NjE2OTY5NzI2NzcxMiwicm9sZU5hbWUiOiLnva4ifSx7InJvbGVJZCI6MTUwMjM4NjUyMjExOTQ2NzAwOCwicm9sZU5hbWUiOiLmiJYifV19.-tmGTaXEyCA-wPKkc-bN1sOkYFAZD0d39q4Ke9srBwo";
//String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwIiwic3ViIjoiYWRtaW4iLCJpc3MiOiJEZW1v57O757ufIiwiYXVkIjoi5pmu6YCa55So5oi3IiwiaWF0IjoxNjQ3MDQzMjA2LCJleHAiOjE2NDcwNDMyMjYsIm5iZiI6MTY0NzA0MzIwNiwibGFzdExvZ2luVGltZSI6MTY0NzA0MzIwNjU4OCwicm9sZUxpc3QiOlt7InJvbGVJZCI6MCwicm9sZU5hbWUiOiLns7vnu5_nrqHnkIblkZgifSx7InJvbGVJZCI6MTUwMjM4NTU1NTAyNjIxMDgxNiwicm9sZU5hbWUiOiLmnLoifSx7InJvbGVJZCI6MTUwMjM4NTg5NDY0MzIwMDAwMCwicm9sZU5hbWUiOiLlv5cifSx7InJvbGVJZCI6MTUwMjM4NjE2OTY5NzI2NzcxMiwicm9sZU5hbWUiOiLnva4ifSx7InJvbGVJZCI6MTUwMjM4NjUyMjExOTQ2NzAwOCwicm9sZU5hbWUiOiLmiJYifV19.2OQ1f6s5TeCmRlUlKUroAlGCnb5XIjhlRHB9IjXZUVU";
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwIiwic3ViIjoiYWRtaW4iLCJpc3MiOiJEZW1v57O757ufIiwiYXVkIjoi5pmu6YCa55So5oi3IiwiaWF0IjoxNjQ3MDQzMjQxLCJleHAiOjE2NDcwNDMyODEsIm5iZiI6MTY0NzA0MzI0MSwibGFzdExvZ2luVGltZSI6MTY0NzA0MzI0MTQ3Nywicm9sZUxpc3QiOlt7InJvbGVJZCI6MCwicm9sZU5hbWUiOiLns7vnu5_nrqHnkIblkZgifSx7InJvbGVJZCI6MTUwMjM4NTU1NTAyNjIxMDgxNiwicm9sZU5hbWUiOiLmnLoifSx7InJvbGVJZCI6MTUwMjM4NTg5NDY0MzIwMDAwMCwicm9sZU5hbWUiOiLlv5cifSx7InJvbGVJZCI6MTUwMjM4NjE2OTY5NzI2NzcxMiwicm9sZU5hbWUiOiLnva4ifSx7InJvbGVJZCI6MTUwMjM4NjUyMjExOTQ2NzAwOCwicm9sZU5hbWUiOiLmiJYifV19.V8q2Y-oxaDyr27pS6WU26qS23m-IkiDswnBDWJENNmo";
        JwtUser jwtUser = parseToken(token);
        System.out.println("jwtUser = " + jwtUser);
    }

}